#include "Uart.h"
Uart::Uart(const std::string &device, unsigned int baudrate, unsigned char dbit, char parity, unsigned char sbit)
{
    m_fd = open(device.c_str(), O_RDWR | O_NOCTTY);
    if (m_fd < 0)
    {
        std::cerr << "open error: " << strerror(errno) << std::endl;
    }
    if (!initialize(device) || !configure(baudrate, dbit, parity, sbit))
    {
        close(m_fd);
        m_fd = -1;
    }
}

Uart::~Uart()
{
    if (m_fd >= 0)
    {
        tcsetattr(m_fd, TCSANOW, &ucfg);
        close(m_fd);
    }
}

bool Uart::initialize(const std::string &device)
{

    if (tcgetattr(m_fd, &ucfg) < 0)
    {
        std::cerr << "tcgetattr error: " << strerror(errno) << std::endl;
        close(m_fd);
        return false;
    }

    return true;
}

bool Uart::configure(unsigned int baudrate, unsigned char dbit, char parity, unsigned char sbit)
{
    cfmakeraw(&ucfg);
    ucfg.c_cflag |= CREAD;

    speed_t speed;
    switch (baudrate)
    {
    case 1200:
        speed = B1200;
        break;
    case 1800:
        speed = B1800;
        break;
    case 2400:
        speed = B2400;
        break;
    case 4800:
        speed = B4800;
        break;
    case 9600:
        speed = B9600;
        break;
    case 19200:
        speed = B19200;
        break;
    case 38400:
        speed = B38400;
        break;
    case 57600:
        speed = B57600;
        break;
    case 115200:
        speed = B115200;
        break;
    case 230400:
        speed = B230400;
        break;
    case 460800:
        speed = B460800;
        break;
    case 500000:
        speed = B500000;
        break;
    default:
        speed = B115200;
        break;
    }

    if (cfsetspeed(&ucfg, speed) < 0)
    {
        std::cerr << "cfsetspeed error: " << strerror(errno) << std::endl;
        return false;
    }

    ucfg.c_cflag &= ~CSIZE;
    switch (dbit)
    {
    case 5:
        ucfg.c_cflag |= CS5;
        break;
    case 6:
        ucfg.c_cflag |= CS6;
        break;
    case 7:
        ucfg.c_cflag |= CS7;
        break;
    case 8:
        ucfg.c_cflag |= CS8;
        break;
    default:
        ucfg.c_cflag |= CS8;
        break;
    }

    switch (parity)
    {
    case 'N':
        ucfg.c_cflag &= ~PARENB;
        ucfg.c_iflag &= ~INPCK;
        break;
    case 'O':
        ucfg.c_cflag |= (PARODD | PARENB);
        ucfg.c_iflag |= INPCK;
        break;
    case 'E':
        ucfg.c_cflag |= PARENB;
        ucfg.c_cflag &= ~PARODD;
        ucfg.c_iflag |= INPCK;
        break;
    default:
        ucfg.c_cflag &= ~PARENB;
        ucfg.c_iflag &= ~INPCK;
        break;
    }

    ucfg.c_cflag = (sbit == 2) ? (ucfg.c_cflag | CSTOPB) : (ucfg.c_cflag & ~CSTOPB);
    ucfg.c_cc[VTIME] = 0;
    ucfg.c_cc[VMIN] = 0;

    if (tcflush(m_fd, TCIOFLUSH) < 0)
    {
        std::cerr << "tcflush error: " << strerror(errno) << std::endl;
        return false;
    }

    if (tcsetattr(m_fd, TCSANOW, &ucfg) < 0)
    {
        std::cerr << "tcsetattr error: " << strerror(errno) << std::endl;
        return false;
    }

    return true;
}
